package myJs.user.workflow.featureSelection

import myJs.Implicits.FieldValue
import myJs.api.Api
import myJs.myPkg.yup.{ConditionOptions, Yup}
import myJs.tool.Tool.messages

import scala.scalajs.js
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._

import scala.concurrent.Future
import scala.scalajs.js.JSConverters._
import scala.collection.mutable
import myJs.Implicits._

/**
 * Created by yz on 9/11/2022
 */
object Schema {

  case class ValidInfo(v: String, valid: Boolean)

  val curTool = FeatureSelection
  val cacheMap = mutable.SeqMap[String, ValidInfo]()

  def cacheTest(key: String)(f: String => Future[Boolean]) = (v: String) => {
    val beforeV = cacheMap.getOrElse(key, ValidInfo("", true))
    if (beforeV.v != v) {
      f(v).map { x =>
        cacheMap.put(key, ValidInfo(v, x))
        x
      }.toJSPromise
    } else {
      Future {
        beforeV.valid
      }.toJSPromise
    }
  }

  def missionNameValidateF(key: String) = cacheTest(key) { v: String =>
    import shared.pojo.Pojo.workflowMission._
    val request = MissionNameCheck.Request(id = curTool.getId, missionName = v)
    Api.workflowMission.missionNameCheck(request).map { response =>
      response.valid
    }
  }

  def fileValidateF(key: String) = cacheTest(key) { v: String =>
    import shared.pojo.Pojo.soft._
    val request = CheckFileName.Request(id = curTool.getId, fileName = v)
    Api.soft.checkFileName(request).map { response =>
      response.valid
    }
  }


  def transformF = (v: Double) => {
    if (v.isNaN) {
      js.undefined
    } else js.defined(v)
  }

  val schema = Yup.`object`().shape(js.Dictionary(
    "missionName" -> Yup.string().required(messages("null")).
      test(name = "checkExist", message = messages("exist"), test = missionNameValidateF("missionName")),
    "file" -> Yup.string().required(messages("null")).
      test(name = "checkNotExist", message = s"${messages("notExist")}", test = fileValidateF("file")),
    "groupFile" -> Yup.string().required(messages("null")).
      test(name = "checkNotExist", message = s"${messages("notExist")}", test = fileValidateF("groupFile")),
    "preprocess" -> Yup.`object`().shape(
      js.Dictionary(
        "datas" -> Yup.array().of(
          Yup.`object`().shape(
            js.Dictionary(
              "colNaRate" -> Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .min(min = 0, message = s"${messages("between", 0, 100)}")
                .max(max = 100, message = s"${messages("between", 0, 100)}"),
              "rowNaRate" -> Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .min(min = 0, message = s"${messages("between", 0, 100)}")
                .max(max = 100, message = s"${messages("between", 0, 100)}"),
              "rsd" -> Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .min(min = 0, message = s"${messages("between", 0, 100)}")
                .max(max = 100, message = s"${messages("between", 0, 100)}"),
              "knnShow" -> Yup.boolean(),
              "knn" -> Yup.number().when("knnShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}")
                  .integer(message = s"${messages("integer")}")
                  .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
              "minShow" -> Yup.boolean(),
              "min" -> Yup.number().when("minShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}")
                  .integer(message = s"${messages("integer")}")
                  .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
              "glogShow" -> Yup.boolean(),
              "glog" -> Yup.number().when("glogShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
              "constantShow" -> Yup.boolean(),
              "constant" -> Yup.number().when("constantShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
              "topNShow" -> Yup.boolean(),
              "topN" -> Yup.number().when("topNShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}")
                  .integer(message = s"${messages("integer")}")
                  .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
              "topPercentShow" -> Yup.boolean(),
              "topPercent" -> Yup.number().when("topPercentShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}")
                  .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
              "removeGroups" -> Yup.array().min(1, s"${messages("null")}"),
            )
          )
        ),
        "trainPercentShow" -> Yup.boolean(),
        "trainPercent" -> Yup.number().when("trainPercentShow", ConditionOptions(
          is = true,
          `then` = Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .integer(message = s"${messages("integer")}")
            .min(min = 0, message = s"${messages("between", 0, 100)}")
            .max(max = 100, message = s"${messages("between", 0, 100)}"),
          otherwise = Yup.number().nullable(true).transform(transformF)
        )),
      )
    ),
    "uniAna" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "uniAnaGroups" -> Yup.array().min(2, messages("atLeast2")),
          "pValue" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .min(min = 0, message = s"${messages("between", 0, 1)}")
            .max(max = 1, message = s"${messages("between", 0, 1)}"),
          "fdr" -> Yup.number().when("useFdr", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}")
              .min(min = 0, message = s"${messages("between", 0, 1)}")
              .max(max = 1, message = s"${messages("between", 0, 1)}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "log2FcShow" -> Yup.boolean(),
          "log2Fc" -> Yup.number().when("log2FcShow", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "mcInfos" -> Yup.array().of(
            Yup.`object`().shape(js.Dictionary(
              "pValueShow" -> Yup.boolean(),
              "pValue" -> Yup.number().when("pValueShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}")
                  .min(min = 0, message = s"${messages("between", 0, 1)}")
                  .max(max = 1, message = s"${messages("between", 0, 1)}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
              "log2FcShow" -> Yup.boolean(),
              "log2Fc" -> Yup.number().when("log2FcShow", ConditionOptions(
                is = true,
                `then` = Yup.number().required(message = s"${messages("null")}")
                  .typeError(message = s"${messages("numeric")}"),
                otherwise = Yup.number().nullable(true).transform(transformF)
              )),
            ))
          ),
          "execTrend" -> Yup.boolean(),
          "selectGroups" -> Yup.array().when("execTrend", ConditionOptions(
            is = true,
            `then` = Yup.array().min(1, s"${messages("null")}"),
            otherwise = Yup.array().min(0)
          ))
        ),
      )
    ),
    "oplsda" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "vip" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}"),
          "q2Y" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}"),
          "q2YB" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}"),
          "group"->Yup.string().required(message =s"${messages("null")}").nullable(false)
        ),
      )
    ),
    "rf" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "groups" -> Yup.array().min(2, messages("atLeast2")),
          "ntree" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .integer(message = s"${messages("integer")}")
            .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
          "mtry" -> Yup.number()
            .when("hasMtry", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "nodesize" -> Yup.number()
            .when("hasNodesize", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "maxnode" -> Yup.number()
            .when("hasMaxnode", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "topM" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .integer(message = s"${messages("integer")}")
            .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
        ),
      )
    ),
    "svm" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "groups" -> Yup.array().min(2, messages("atLeast2")),
          "cost" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .integer(message = s"${messages("integer")}")
            .min(min = 0, message = s"${messages("greaterThanOrEqual", 0)}"),
          "tolerance" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}"),
          "epsilon" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}"),
          "gamma" -> Yup.number()
            .when("kernel", ConditionOptions(
              is = (v: String) => {
                List("polynomial", "radial", "sigmoid").exists { x =>
                  x == v
                }
              },
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .min(min = 0, message = s"${messages("between", 0, 1)}")
                .max(max = 1, message = s"${messages("between", 0, 1)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "coef0" -> Yup.number()
            .when("kernel", ConditionOptions(
              is = (v: String) => {
                List("polynomial", "sigmoid").exists(v == _)
              },
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .min(min = 0, message = s"${messages("greaterThanOrEqual", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "degree" -> Yup.number()
            .when("kernel", ConditionOptions(
              is = (v: String) => {
                v == "polynomial"
              },
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .min(min = 0, message = s"${messages("greaterThanOrEqual", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "topM" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .integer(message = s"${messages("integer")}")
            .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
        ),
      )
    ),
    "boruta" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "groups" -> Yup.array().min(2, messages("atLeast2")),
          "maxRun" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .integer(message = s"${messages("integer")}")
            .moreThan(more = 10, message = s"${messages("greaterThan", 10)}"),
          "pValue" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .min(min = 0, message = s"${messages("between", 0, 1)}")
            .max(max = 1, message = s"${messages("between", 0, 1)}"),
        ),
      )
    ),
    "diagnoseAna" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "group"->Yup.string().required(message =s"${messages("null")}").nullable(false),
          "externalFile" -> Yup.string().when("hasExternal", ConditionOptions(
            is = true,
            `then` = Yup.string().required(messages("null")).
              test(name = "checkNotExist", message = s"${messages("notExist")}", test = fileValidateF("externalFile")),
            otherwise = Yup.string()
          )),
          "externalGroupFile" -> Yup.string().when("hasExternal", ConditionOptions(
            is = true,
            `then` = Yup.string().required(messages("null")).
              test(name = "checkNotExist", message = s"${messages("notExist")}", test = fileValidateF("externalGroupFile")),
            otherwise = Yup.string()
          )),
          "ntree" -> Yup.number().when("runRf", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}")
              .integer(message = s"${messages("integer")}")
              .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "mtryShow" -> Yup.boolean(),
          "mtry" -> Yup.number()
            .when("mtryShow", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "nodesizeShow" -> Yup.boolean(),
          "nodesize" -> Yup.number()
            .when("nodesizeShow", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "maxnodeShow" -> Yup.boolean(),
          "maxnode" -> Yup.number()
            .when("maxnodeShow", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "gbNTree" -> Yup.number().when("runGb", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}")
              .integer(message = s"${messages("integer")}")
              .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "depth" -> Yup.number().when("runGb", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}")
              .integer(message = s"${messages("integer")}")
              .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "fraction" -> Yup.number().when("runGb", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}")
              .min(min = 0, message = s"${messages("between", 0, 1)}")
              .max(max = 1, message = s"${messages("between", 0, 1)}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "cost" -> Yup.number().when("runSvm", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}")
              .integer(message = s"${messages("integer")}")
              .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "tolerance" -> Yup.number().when("runSvm", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "epsilon" -> Yup.number().when("runSvm", ConditionOptions(
            is = true,
            `then` = Yup.number().required(message = s"${messages("null")}")
              .typeError(message = s"${messages("numeric")}"),
            otherwise = Yup.number().nullable(true).transform(transformF)
          )),
          "gammaShow" -> Yup.boolean(),
          "gamma" -> Yup.number()
            .when("gammaShow", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .min(min = 0, message = s"${messages("between", 0, 1)}")
                .max(max = 1, message = s"${messages("between", 0, 1)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "coef0Show" -> Yup.boolean(),
          "coef0" -> Yup.number()
            .when("coef0Show", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .min(min = 0, message = s"${messages("greaterThanOrEqual", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
          "degreeShow" -> Yup.boolean(),
          "degree" -> Yup.number()
            .when("degreeShow", ConditionOptions(
              is = true,
              `then` = Yup.number().required(message = s"${messages("null")}")
                .typeError(message = s"${messages("numeric")}")
                .integer(message = s"${messages("integer")}")
                .min(min = 0, message = s"${messages("greaterThanOrEqual", 0)}"),
              otherwise = Yup.number().nullable(true).transform(transformF)
            )),
        ),
      )
    ),
    "plsda" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "groups" -> Yup.array().min(2, messages("atLeast2")),
          "vip" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}"),
        ),
      )
    ),
    "pca" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "groups" -> Yup.array().min(1, messages("null")),
        ),
      )
    ),
    "cor" -> Yup.array().of(
      Yup.`object`().shape(
        js.Dictionary(
          "coe" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .min(min = 0, message = s"${messages("between", 0, 1)}")
            .max(max = 1, message = s"${messages("between", 0, 1)}"),
          "p" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .min(min = 0, message = s"${messages("between", 0, 1)}")
            .max(max = 1, message = s"${messages("between", 0, 1)}"),
          "fdr" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .min(min = 0, message = s"${messages("between", 0, 1)}")
            .max(max = 1, message = s"${messages("between", 0, 1)}"),
          "nodeSize" -> Yup.number().required(message = s"${messages("null")}")
            .typeError(message = s"${messages("numeric")}")
            .integer(message = s"${messages("integer")}")
            .moreThan(more = 0, message = s"${messages("greaterThan", 0)}"),
          "extraFile" -> Yup.string().required(messages("null")).
            test(name = "checkNotExist", message = s"${messages("notExist")}", test = fileValidateF("extraFile")),
          "confounderFile" -> Yup.string().when("hasConfounder", ConditionOptions(
            is = true,
            `then` = Yup.string().required(messages("null")).
              test(name = "checkNotExist", message = s"${messages("notExist")}", test = fileValidateF("confounderFile")),
            otherwise = Yup.string()
          )),

        ),
      )
    ),
  ))


}
